// the lock server implementation

#include "lock_server.h"
#include <map>
#include <sstream>
#include <iostream>
#include <stdio.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <pthread.h>

using namespace std;
lock_server::lock_server():
	nacquire (0)
{
	map<lock_protocol::lockid_t, int> tLock;
	locks = tLock;
	map<lock_protocol::lockid_t, pair<pthread_mutex_t, pthread_cond_t> > tCon;
	concur = tCon;
}

lock_server::~lock_server()
{
}

lock_protocol::status
lock_server::stat(int clt, lock_protocol::lockid_t lid, int &r)
{
	lock_protocol::status ret = lock_protocol::OK;
	printf("stat request from clt %d\n", clt);
	r = nacquire;
	return ret;
}


lock_protocol::status
lock_server::acquire(int clt, lock_protocol::lockid_t lid, int &r)
{
	lock_protocol::status ret = lock_protocol::OK;
	printf("Received acquire from %d\n", clt);

	pthread_mutex_t mut;
	pthread_cond_t con;

	map<lock_protocol::lockid_t, pair<pthread_mutex_t, pthread_cond_t> >::iterator ite = concur.find(lid);
	if(ite == concur.end() )
	{
		cout << "If'd\n" << endl;
		pthread_mutex_init(&mut, NULL);
		pthread_cond_init(&con, NULL);
		concur.insert( pair<lock_protocol::lockid_t, pair<pthread_mutex_t, pthread_cond_t> > (lid, pair<pthread_mutex_t, pthread_cond_t> (mut, con)));	
	}
	else
	{
		mut = ite->second.first;
		con = ite->second.second;
	}
	assert(pthread_mutex_lock(&mut) == 0);

	concur.erase(lid);
	concur.insert(pair<lock_protocol::lockid_t, pair<pthread_mutex_t, pthread_cond_t> > (lid, pair<pthread_mutex_t, pthread_cond_t> (mut, con)));

	map<lock_protocol::lockid_t, int>::iterator it = locks.find(lid);
	if(it != locks.end())
	{
		while(it->second)
		{
			assert(pthread_cond_wait(&con, &mut) == 0);
			it = locks.find(lid);
		}
		locks.erase(it);
		locks.insert( pair<lock_protocol::lockid_t, int> (lid, 1) );
	}
	else
	{
		cout << "Else'd\n" << endl;
		locks.insert( pair<lock_protocol::lockid_t, int> (lid, 1));
	}
	cout << "Unlocked\n" << endl;
	cout << "Exiting Acquire\n" << endl;
	return ret;
}

lock_protocol::status
lock_server::release(int clt, lock_protocol::lockid_t lid, int &r)
{
	cout << "In release\n" << endl;
	lock_protocol::status ret = lock_protocol::OK;
	printf("Received release from %d\n", clt);
	locks.erase(lid);
	locks.insert(pair<lock_protocol::lockid_t, int> (lid, 0));
	
	map<lock_protocol::lockid_t, pair<pthread_mutex_t, pthread_cond_t> >::iterator it = concur.find(lid);
	pthread_mutex_t mut = it->second.first;
	pthread_cond_t con = it->second.second;
	assert(pthread_cond_signal(&con) == 0);
	assert(pthread_mutex_unlock(&mut) == 0);
	
	concur.erase(lid);
	concur.insert(pair<lock_protocol::lockid_t, pair<pthread_mutex_t, pthread_cond_t> > (lid, pair<pthread_mutex_t, pthread_cond_t> (mut, con)));

	cout << "Unlocking\n" << endl;
	return ret;
}
